/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * SocialNetPanel.java
 *
 * Created on Jul 19, 2009, 11:29:22 AM
 */
package JungSocialNetPackage;

import LabelPanelPackage.LabelPanel;
import multiarray.MultiArray;
import SocialMatrixPackage.SocialMatrix;
//import edu.uci.ics.jung.algorithms.layout3d.SpringLayout;
import edu.uci.ics.jung.graph.SparseGraph;
import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
import edu.uci.ics.jung.visualization.VisualizationModel;
//import edu.uci.ics.jung.visualization3d.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Paint;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Timer;
import java.util.Vector;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import org.apache.commons.collections15.Transformer;

/**
 *
 * @author Heather
 */
public class CCPVSocialNetPanel extends javax.swing.JPanel
{

  /** Creates new form SocialNetPanel */
  public CCPVSocialNetPanel()
  {
    initComponents();
    legendPanel.setBackground(Color.white);
    legendScrollPane.add(legendPanel);
    legendScrollPane.setViewportView(legendPanel);
    socialNetAscriptiveTree.setSize(170, 430);
    socialNetAscriptiveTree.setPreferredSize(new Dimension(170, 430));
    setupNet();
    setupAltruismTest();
    //setupMalayAltruismTest();
    setupVVChangeListener();
  }

  /** This method is called from within the constructor to
   * initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is
   * always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    socialNetContainer = new javax.swing.JPanel();
    jLabel1 = new javax.swing.JLabel();
    zoomOutButton = new javax.swing.JButton();
    zoomInButton = new javax.swing.JButton();
    stopButton = new javax.swing.JButton();
    forceAdjustmentSlider = new javax.swing.JSlider();
    jLabel2 = new javax.swing.JLabel();
    socialNetTitle = new javax.swing.JLabel();
    filterLabel = new javax.swing.JLabel();
    toggleZeroWeightsButton = new javax.swing.JButton();
    rerollButton = new javax.swing.JButton();
    legendScrollPane = new javax.swing.JScrollPane();
    jLabel3 = new javax.swing.JLabel();
    jScrollPane1 = new javax.swing.JScrollPane();
    socialNetAscriptiveTree = new javax.swing.JTree();

    setBackground(new java.awt.Color(255, 255, 204));
    setLayout(null);

    socialNetContainer.setBackground(new java.awt.Color(204, 204, 255));
    socialNetContainer.setPreferredSize(new java.awt.Dimension(520, 520));
    socialNetContainer.setLayout(null);
    add(socialNetContainer);
    socialNetContainer.setBounds(190, 60, 520, 460);

    jLabel1.setFont(new java.awt.Font("Tahoma", 2, 18)); // NOI18N
    jLabel1.setText("Filter Selection");
    add(jLabel1);
    jLabel1.setBounds(10, 40, 170, 20);

    zoomOutButton.setText("zoom out");
    zoomOutButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        zoomOutButtonActionPerformed(evt);
      }
    });
    add(zoomOutButton);
    zoomOutButton.setBounds(190, 530, 100, 23);

    zoomInButton.setText("zoom in");
    zoomInButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        zoomInButtonActionPerformed(evt);
      }
    });
    add(zoomInButton);
    zoomInButton.setBounds(290, 530, 100, 23);

    stopButton.setText("STOP");
    stopButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        stopButtonActionPerformed(evt);
      }
    });
    add(stopButton);
    stopButton.setBounds(390, 530, 100, 23);

    forceAdjustmentSlider.setMaximum(10000);
    forceAdjustmentSlider.setValue(0);
    forceAdjustmentSlider.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(javax.swing.event.ChangeEvent evt) {
        forceAdjustmentSliderStateChanged(evt);
      }
    });
    add(forceAdjustmentSlider);
    forceAdjustmentSlider.setBounds(490, 540, 220, 23);

    jLabel2.setFont(new java.awt.Font("Tahoma", 1, 11));
    jLabel2.setText("Adjust spring forces");
    add(jLabel2);
    jLabel2.setBounds(490, 520, 220, 14);

    socialNetTitle.setFont(new java.awt.Font("Tahoma", 1, 18)); // NOI18N
    socialNetTitle.setText("Social Net Spring Forces Graph");
    add(socialNetTitle);
    socialNetTitle.setBounds(10, 4, 700, 30);

    filterLabel.setFont(new java.awt.Font("Tahoma", 3, 12)); // NOI18N
    filterLabel.setText("NO filtering applied");
    add(filterLabel);
    filterLabel.setBounds(190, 40, 520, 20);

    toggleZeroWeightsButton.setText("Show zero weights");
    toggleZeroWeightsButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        toggleZeroWeightsButtonActionPerformed(evt);
      }
    });
    add(toggleZeroWeightsButton);
    toggleZeroWeightsButton.setBounds(10, 530, 170, 23);

    rerollButton.setText("Reset Network");
    rerollButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        rerollButtonActionPerformed(evt);
      }
    });
    add(rerollButton);
    rerollButton.setBounds(10, 500, 170, 23);

    legendScrollPane.setBackground(new java.awt.Color(255, 255, 255));
    add(legendScrollPane);
    legendScrollPane.setBounds(720, 60, 270, 500);

    jLabel3.setFont(new java.awt.Font("Tahoma", 2, 18)); // NOI18N
    jLabel3.setText("Legend");
    add(jLabel3);
    jLabel3.setBounds(720, 40, 100, 22);

    socialNetAscriptiveTree.addTreeSelectionListener(new javax.swing.event.TreeSelectionListener() {
      public void valueChanged(javax.swing.event.TreeSelectionEvent evt) {
        socialNetAscriptiveTreeValueChanged(evt);
      }
    });
    jScrollPane1.setViewportView(socialNetAscriptiveTree);

    add(jScrollPane1);
    jScrollPane1.setBounds(10, 60, 170, 430);
  }// </editor-fold>//GEN-END:initComponents

  private void zoomOutButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomOutButtonActionPerformed
    if (maxEdgeLength - 100 >= 100)
    {
      maxEdgeLength -= ZOOM_INCREMENT;
    }
    if (maxEdgeLength - 100 <= 100)
    {
      zoomOutButton.setEnabled(false);
    }
  }//GEN-LAST:event_zoomOutButtonActionPerformed

  private void zoomInButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_zoomInButtonActionPerformed
    zoomOutButton.setEnabled(true);
    maxEdgeLength += ZOOM_INCREMENT;
  }//GEN-LAST:event_zoomInButtonActionPerformed

  private void stopButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_stopButtonActionPerformed
  {//GEN-HEADEREND:event_stopButtonActionPerformed
    // TODO add your handling code here:
    layout2D.setDone(!layout2D.done());
}//GEN-LAST:event_stopButtonActionPerformed

  private void filterNodesByAscriptives(Vector<DefaultMutableTreeNode> selectedNodes)
  {
    // first we need to fill out the restore vertices if we haven't already
    if (restoreVertices == null)
    {
      restoreVertices = new Vector<SocialNetVertex>();
      Collection<SocialNetVertex> sngVCollection = sng.getVertices();
      Iterator<SocialNetVertex> vertexIt = sngVCollection.iterator();
      while (vertexIt.hasNext())
      {
        restoreVertices.add(vertexIt.next());
      }
    }
    if (restoreEdges == null)
    {
      restoreEdges = new Vector<SocialNetEdge>();
      Collection<SocialNetEdge> sngECollection = sng.getEdges();
      Iterator<SocialNetEdge> edgeIt = sngECollection.iterator();
      while (edgeIt.hasNext())
      {
        restoreEdges.add(edgeIt.next());
      }
    }

    //DefaultMutableTreeNode selected = (DefaultMutableTreeNode) socialNetAscriptiveTree.getLastSelectedPathComponent();

    // first remove the edges
    Collection<SocialNetEdge> edgeC = sng.getEdges();
    Iterator<SocialNetEdge> edgeIterator = edgeC.iterator();
    Vector<SocialNetEdge> removalEList = new Vector<SocialNetEdge>();
    while (edgeIterator.hasNext())
    {
      SocialNetEdge e = edgeIterator.next();
      removalEList.add(e);
    }
    for (int i = 0; i < removalEList.size(); i++)
    {
      sng.removeEdge(removalEList.get(i));
    }

    // next remove the vertices
    Collection<SocialNetVertex> vertexC = sng.getVertices();
    Iterator<SocialNetVertex> vertexIterator = vertexC.iterator();
    Vector<SocialNetVertex> removalVList = new Vector<SocialNetVertex>();
    while (vertexIterator.hasNext())
    {
      SocialNetVertex v = vertexIterator.next();
      removalVList.add(v);
    }
    for (int i = 0; i < removalVList.size(); i++)
    {
      sng.removeVertex(removalVList.get(i));
    }


    // add new vertices
    for (int z = 0; z < selectedNodes.size(); z++)
    {
      DefaultMutableTreeNode selected = selectedNodes.get(z);

      for (int i = 0; i < selected.getChildCount(); i++)
      {
        DefaultMutableTreeNode aChild = (DefaultMutableTreeNode) selected.getChildAt(i);
        SocialNetVertex v = new SocialNetVertex();
        v.name = (String) aChild.getUserObject();
        v.number = i;
        v.setRandomColor();

        Vector<String> nodeAscriptives = new Vector<String>();
        Vector<String> ascriptiveCategories = altruismMatrix.getAscriptiveCategories();
        for (int j = 0; j < ascriptiveCategories.size(); j++)
        {
          String categoryName = ascriptiveCategories.get(j);
          // if the ascriptive loop is at the category selected, we add the child name... otherwise
          // we add the category name
          if (((String) selected.getUserObject()).equals(categoryName))
          {
            nodeAscriptives.add(v.name);
          }
          else
          {
            nodeAscriptives.add(categoryName);
          }
        }

        Vector<int[]> newRepresentedGroups = altruismMatrix.getRepresentedGroups(nodeAscriptives);
        v.representedGroups = newRepresentedGroups;
        sng.addVertex(v);

        // handle labels
        vertexLabels.clear();
        createLabels();
        arrangeLabelOrders();
      }
    }

    // add new edges
    vertexC = sng.getVertices();
    vertexIterator = vertexC.iterator();
    while (vertexIterator.hasNext())
    {
      SocialNetVertex sources = vertexIterator.next();
      Iterator<SocialNetVertex> targetIt = vertexC.iterator();
      while (targetIt.hasNext())
      {
        SocialNetVertex targets = targetIt.next();
        double altValue = altruismMatrix.getAverageAltruismMultipleSourcesAndTargetsWithPopulation(sources.representedGroups, targets.representedGroups, population);
        SocialNetEdge e = new SocialNetEdge();
        e.socialValue = altValue;
        sng.addEdge(e, sources, targets);
      }
    }

    repaint();
  }

  private void forceAdjustmentSliderStateChanged(javax.swing.event.ChangeEvent evt)//GEN-FIRST:event_forceAdjustmentSliderStateChanged
  {//GEN-HEADEREND:event_forceAdjustmentSliderStateChanged
    zeroAltruismValue = Integer.MAX_VALUE * (forceAdjustmentSlider.getValue() / forceAdjustmentSlider.getMaximum());

    // now that the zero altruism value is set, set all spring values
    Collection<SocialNetEdge> edgeCollection = sng.getEdges();
    Iterator<SocialNetEdge> edgeIterator = edgeCollection.iterator();
    while (edgeIterator.hasNext())
    {
      SocialNetEdge e = edgeIterator.next();
      setEdgeSpringStrength(e);
    }
  }//GEN-LAST:event_forceAdjustmentSliderStateChanged

  private void toggleZeroWeightsButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_toggleZeroWeightsButtonActionPerformed
  {//GEN-HEADEREND:event_toggleZeroWeightsButtonActionPerformed
    if (!showingZeroWeights)
    {
      toggleZeroWeightsButton.setText("Don't show zero weights");
    }
    else
    {
      toggleZeroWeightsButton.setText("Show zero weights");
    }

    showingZeroWeights = !showingZeroWeights;

    // NOTE: THIS METHOD IS DEPENDENT ON THE MODE OF TESTING... NEED TO ELIMINATE THIS WHEN TESTING IS OVER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    if (mode.equals("MALAY TEST"))
    {
      setupMalayAltruismTest();
    }
    else
    {
      if (mode.equals("ALTRUISM TEST"))
      {
        setupAltruismTest();
      }
      else
      {
        setVerticesAndEdges(socialMatrix, population);
      }
    }
  }//GEN-LAST:event_toggleZeroWeightsButtonActionPerformed

  private void rerollButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_rerollButtonActionPerformed
  {//GEN-HEADEREND:event_rerollButtonActionPerformed
    reRoll();
  }//GEN-LAST:event_rerollButtonActionPerformed

  private void socialNetAscriptiveTreeValueChanged(javax.swing.event.TreeSelectionEvent evt)//GEN-FIRST:event_socialNetAscriptiveTreeValueChanged
  {//GEN-HEADEREND:event_socialNetAscriptiveTreeValueChanged
    // TODO add your handling code here:
    TreePath[] selectedPaths = socialNetAscriptiveTree.getSelectionPaths();
    Vector<DefaultMutableTreeNode> selectedNodes = new Vector<DefaultMutableTreeNode>();
    for (int i = 0; i < selectedPaths.length; i++)
    {
      DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) selectedPaths[i].getLastPathComponent();
      if (!selectedNode.isLeaf())
      {
        selectedNodes.add(selectedNode);
      }
    }

    filterNodesByAscriptives(selectedNodes);
  }//GEN-LAST:event_socialNetAscriptiveTreeValueChanged

  private void reRoll()
  {
    // NOTE: THIS METHOD IS DEPENDENT ON THE MODE OF TESTING... NEED TO ELIMINATE THIS WHEN TESTING IS OVER!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    if (mode.equals("MALAY TEST"))
    {
      setupMalayAltruismTest();
    }
    else
    {
      if (mode.equals("ALTRUISM TEST"))
      {
        setupAltruismTest();
      }
      else
      {
        setVerticesAndEdges(socialMatrix, population);
      }
    }

    int labelCount = 0;
    for (int i = 0; i < socialNetContainer.getComponentCount(); i++)
    {
      Component c = socialNetContainer.getComponent(i);
      if (c instanceof JLabel)
      {
        labelCount++;
      }
    }

    Collection<SocialNetVertex> vertC = sng.getVertices();
    System.out.println("THERE SHOULD BE " + vertC.size() + " NUMBER OF LABELES");
    System.out.println("LABEL COUNT IS: " + labelCount);
    System.out.println("");
  }

  private void setEdgeSpringStrength(SocialNetEdge e)
  {
    double eAbsValue = Math.abs(e.socialValue);
    double x1 = 0;
    double x2 = forceAdjustmentSlider.getMaximum();
    double y1 = zeroAltruismValue;
    double y2 = Integer.MAX_VALUE;

    double slope = (y1 - y2) / (x1 - x2);
    double newSpringStrength = slope * eAbsValue + zeroAltruismValue;
    e.springStrength = newSpringStrength;
  }

  // here, we filter the nodes by ascriptive characteristics
  private void setupVVChangeListener()
  {
    vv2D.addChangeListener(new ChangeListener()
    {

      public void stateChanged(ChangeEvent evt)
      {
        setAllVertexLabels();
      }
    });
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JLabel filterLabel;
  private javax.swing.JSlider forceAdjustmentSlider;
  private javax.swing.JLabel jLabel1;
  private javax.swing.JLabel jLabel2;
  private javax.swing.JLabel jLabel3;
  private javax.swing.JScrollPane jScrollPane1;
  private javax.swing.JScrollPane legendScrollPane;
  private javax.swing.JButton rerollButton;
  private javax.swing.JTree socialNetAscriptiveTree;
  private javax.swing.JPanel socialNetContainer;
  private javax.swing.JLabel socialNetTitle;
  private javax.swing.JButton stopButton;
  private javax.swing.JButton toggleZeroWeightsButton;
  private javax.swing.JButton zoomInButton;
  private javax.swing.JButton zoomOutButton;
  // End of variables declaration//GEN-END:variables
  private int maxEdgeLength = 400;
  private final int ZOOM_INCREMENT = 100;
  private SparseGraph<SocialNetVertex, SocialNetEdge> sng = new SparseGraph<SocialNetVertex, SocialNetEdge>();
  private Random randGen = new Random();
  // 2d layout
  //private edu.uci.ics.jung.algorithms.layout.SpringLayout<SocialNetVertex, SocialNetEdge> layout2D;
  private SocialNetSpringLayout<SocialNetVertex, SocialNetEdge> layout2D;
  // 2d viewer
  private edu.uci.ics.jung.visualization.VisualizationViewer vv2D;
  // this is for the 2d mode
  private VisualizationModel visualizationModel2D;
  private DefaultModalGraphMouse graphMouse;
  private static final long BUTTON_DELAY_TIME = 8000;
  private Timer delayTimer = new Timer();
  // stores edges that have zero for their social value
  private Vector<SocialNetEdge> zeroEdges = new Vector<SocialNetEdge>();
  // stores the labels for socialnetvertices
  private Map<SocialNetVertex, JLabel> vertexLabels = new HashMap<SocialNetVertex, JLabel>();
  // when the user clicks and drags, the offset tells us how far to move the points so they
  // stay on top of the vertices
  private HashMap<JLabel, Point> labelOffsets = new HashMap<JLabel, Point>();
  private SocialMatrix altruismMatrix;
  private Vector<SocialNetVertex> allVertexCombos = new Vector<SocialNetVertex>();
  // if true, users can use the confirmascriptivebutton to filter nodes
  private boolean filterOK = false;
  // stores the information that builds the sparse graph
  private MultiArray<Integer> population;
  private SocialMatrix socialMatrix;
  private double zeroAltruismValue = 0;
  private Color socialNetLabelColor = new Color(0, 0, 255);
  private boolean showingZeroWeights = true;
  private String mode = "NONE";
  // these are used to restore the mapping when the reset function is used.
  // fill these in before filtering is applied
  private Vector<SocialNetVertex> restoreVertices;
  private Vector<SocialNetEdge> restoreEdges;
  private Point prevClickedPoint = null;
  private LabelPanel legendPanel = new LabelPanel();
  //private Dimension treeDimension = new Dimension(170, 430);

  private void setupNet()
  {
    Dimension preferredSize = socialNetContainer.getSize();
    // 2d setup
    layout2D = new SocialNetSpringLayout(sng, new Transformer<SocialNetEdge, Integer>()
    {

      public Integer transform(SocialNetEdge e)
      {
        //return (int) e.length;
        return (int) (convertFeelingsIntoLength(e.socialValue));
      }
    });
    layout2D.setForceMultiplier(Integer.MAX_VALUE);
    layout2D.setRepulsionRange(100);
    layout2D.setSize(preferredSize); // sets the initial size of the space

    visualizationModel2D = new DefaultVisualizationModel(layout2D, preferredSize);
    vv2D = new edu.uci.ics.jung.visualization.VisualizationViewer(visualizationModel2D, preferredSize);
    vv2D.setGraphLayout(layout2D);
    vv2D.setPreferredSize(preferredSize); //Sets the viewing area size
    vv2D.setSize(preferredSize);
    vv2D.setBackground(Color.white);

    graphMouse = new DefaultModalGraphMouse();
    vv2D.setGraphMouse(graphMouse);
    // add a listener for ToolTips

    vv2D.setVertexToolTipTransformer(new ToStringLabeller()
    {

      public String transform(Object v)
      {
        if (v instanceof SocialNetVertex)
        {
          return ((SocialNetVertex) v).name;
        }
        else
        {
          return "NO NAME";
        }
      }
    });

    // add a listener for edges
    vv2D.setEdgeToolTipTransformer(new ToStringLabeller()
    {

      public String transform(Object e)
      {
        if (e instanceof SocialNetEdge)
        {
          return ((SocialNetEdge) e).name;
        }
        else
        {
          return "NO NAME";
        }
      }
    });

    vv2D.getRenderContext().setVertexFillPaintTransformer(new Transformer<SocialNetVertex, Paint>()
    {

      public Paint transform(SocialNetVertex v)
      {
        return v.color;
      }
    });

    // add listeners to vv2d
    vv2D.addMouseListener(new java.awt.event.MouseAdapter()
    {

      public void mouseClicked(java.awt.event.MouseEvent evt)
      {
      }

      public void mouseEntered(java.awt.event.MouseEvent evt)
      {
      }

      public void mouseExited(java.awt.event.MouseEvent evt)
      {
      }

      public void mousePressed(java.awt.event.MouseEvent evt)
      {
        Point clickP = evt.getPoint();

        prevClickedPoint = clickP;
      }

      public void mouseReleased(java.awt.event.MouseEvent evt)
      {
        prevClickedPoint = null;
      }
    });
    vv2D.addMouseMotionListener(new java.awt.event.MouseMotionAdapter()
    {

      public void mouseDragged(java.awt.event.MouseEvent evt)
      {
        Point mouseP = evt.getPoint();
        int mouseXMovement = prevClickedPoint.x - mouseP.x;
        int mouseYMovement = prevClickedPoint.y - mouseP.y;

        Collection<Point> allPoints = labelOffsets.values();
        Iterator<Point> pIt = allPoints.iterator();
        while (pIt.hasNext())
        {
          Point p = pIt.next();
          int newX = p.x + mouseXMovement;
          int newY = p.y + mouseYMovement;

          Point newP = new Point(newX, newY);
        //p = newP;
        //labelOffsets.put(jLabel1, newP)
        }

        setAllVertexLabels();
      }

      public void mouseMoved(java.awt.event.MouseEvent evt)
      {
      }
    });

    socialNetContainer.removeAll();
    createLabels();
    socialNetContainer.add(vv2D);
    arrangeLabelOrders();

    System.gc();
  }

  public void setupGenericTest()
  {
  }

  private void setAscriptiveTree(SocialMatrix sm)
  {
    JTree smTree = sm.getAscriptiveTree();


    // all the roots
    DefaultMutableTreeNode smRoot = (DefaultMutableTreeNode) smTree.getModel().getRoot();
    DefaultMutableTreeNode root = (DefaultMutableTreeNode) socialNetAscriptiveTree.getModel().getRoot();


    root.removeAllChildren();

    Vector<DefaultMutableTreeNode> queue = new Vector<DefaultMutableTreeNode>();
    // stores parents
    HashMap<DefaultMutableTreeNode, DefaultMutableTreeNode> parentList = new HashMap<DefaultMutableTreeNode, DefaultMutableTreeNode>();
    parentList.put(smRoot, root);

    // add roots children
    for (int i = 0; i < smRoot.getChildCount(); i++)
    {
      queue.add((DefaultMutableTreeNode) smRoot.getChildAt(i));
    }


    // use bfs to fill out tree
    while (queue.size() > 0)
    {
      // pop top
      DefaultMutableTreeNode popped = queue.get(0);
      queue.remove(popped);
      String popString = (String) popped.getUserObject();
      System.out.println("popString: " + popString);
      DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(popString);
      parentList.put(popped, newNode);

      DefaultMutableTreeNode parent = parentList.get(popped.getParent());
      parent.add(newNode);

      // queue children
      for (int i = 0; i < popped.getChildCount(); i++)
      {
        queue.add((DefaultMutableTreeNode) popped.getChildAt(i));
      }
    }


    socialNetAscriptiveTree.updateUI();
  }

  public void setVerticesAndEdges(SocialMatrix feelings, MultiArray<Integer> population)
  {
    boolean p = false;
    this.population = population;
    this.socialMatrix = feelings;

    filterOK = true;
    // first clear the graph
    sng = new SparseGraph();

    Vector<int[]> allCombinations = feelings.getAllCombinations();
    for (int i = 0; i < allCombinations.size(); i++)
    {
      int[] combo = allCombinations.get(i);
      int comboPop = population.getElementAtIndex(allCombinations.get(i));

      if (!p)
      {
        p = true;

        String s = "";
        for (int gi : combo)
        {
          s += gi + ", ";
        }
        System.out.println("this is rep group: " + s);
      }

      // only add vertices that have more than zero pop
      if (comboPop > 0)
      {
        SocialNetVertex newVertex = new SocialNetVertex();
        newVertex.number = i;
        Vector<int[]> repGroups = new Vector<int[]>();

        repGroups.add(allCombinations.get(i));
        newVertex.representedGroups = repGroups;

        String newName = "";
        Vector<String> comboStrings = feelings.convertIndexIntoStringVector(combo);
        for (int j = 0; j < comboStrings.size(); j++)
        {
          newName += comboStrings.get(j) + " * ";
        }

        newVertex.name = newName;
        newVertex.setRandomColor();
        allVertexCombos.add(newVertex);

        double chance = randGen.nextDouble();
        // FOR NOW WE ARE ONLY ACCEPTING 50 PERCENT OF THE COMBINATINOS.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //if (chance > 0.5)
        //{
        sng.addVertex(newVertex);
      //}
      }
    }

    Vector<SocialNetVertex> seen = new Vector<SocialNetVertex>();
    Collection vertCollection = sng.getVertices();
    Iterator sourceIt = vertCollection.iterator();
    while (sourceIt.hasNext())
    {
      SocialNetVertex sourcesVertex = (SocialNetVertex) sourceIt.next();
      seen.add(sourcesVertex);
      Vector<int[]> sources = sourcesVertex.representedGroups;

      Iterator targetIt = vertCollection.iterator();
      while (targetIt.hasNext())
      {
        SocialNetVertex targetsVertex = (SocialNetVertex) targetIt.next();
        if (!seen.contains(targetsVertex))
        {
          Vector<int[]> targets = targetsVertex.representedGroups;
          double sourceToTargetValue = feelings.getAverageAltruismMultipleSourcesAndTargetsWithPopulation(sources, targets, population);
          double targetToSourceValue = feelings.getAverageAltruismMultipleSourcesAndTargetsWithPopulation(targets, sources, population);
          // right now dividing by 2... which gives equal weight.  NEED TO CHANGE THIS LATER
          double edgeValue = (sourceToTargetValue + targetToSourceValue) / 2;
          double edgeLength = convertFeelingsIntoLength(edgeValue);
          SocialNetEdge newEdge = new SocialNetEdge();
          newEdge.socialValue = edgeValue;
          newEdge.length = edgeLength;
          newEdge.name = "source: " + sourcesVertex.number + ", target: " + targetsVertex.number + ", length: " + (int) newEdge.length;

          if (!((edgeValue == 0) && (!showingZeroWeights)))
          {
            sng.addEdge(newEdge, sourcesVertex, targetsVertex);
          }
        }
      }
    }

    // set the tree
    setAscriptiveTree(feelings);
    //System.out.println("social net tree size: " + socialNetAscriptiveTree.getSize());
    createLabels();
    setupNet();
  //repaint();
  }

  public void setupAltruismTest()
  {
    mode = "ALTRUISM TEST";
    SocialMatrix feelingsMatrix = new SocialMatrix(new JTree());
    altruismMatrix = feelingsMatrix;
    int[] dimensions =
    {
      4, 4, 4
    };
    population = new MultiArray<Integer>(dimensions);
    Vector<int[]> allCombinations = feelingsMatrix.getAllCombinations();
    // setting populations to random between 0 and 10000
    for (int i = 0; i < allCombinations.size(); i++)
    {
      //System.out.println(getArrayString(allCombinations.get(i)));
      population.setElementAtIndex(allCombinations.get(i), randGen.nextInt(1000));
    }

    // setting feelings
    for (int i = 0; i < allCombinations.size(); i++)
    {
      int[] source = allCombinations.get(i);
      for (int j = 0; j < allCombinations.size(); j++)
      {
        int[] target = allCombinations.get(j);

        if ((i % 2) == (j % 2))
        {
          feelingsMatrix.setAltruism(source, target, randGen.nextDouble());
        }
        else
        {
          feelingsMatrix.setAltruism(source, target, -randGen.nextDouble());
        }
      }
    }

    setVerticesAndEdges(feelingsMatrix, population);
  }

  public void setupMalayAltruismTest()
  {
    mode = "MALAY TEST";
    // clear the nodes
    sng = new SparseGraph<SocialNetVertex, SocialNetEdge>();

    // for deciding malay ==> others
    //Map<String, SocialNetVertex> otherMap = new HashMap<String, SocialNetVertex>();
    // for deciding others ==> malay
    Vector<SocialNetVertex> allOthers = new Vector<SocialNetVertex>();
    String[] nonMalayNames =
    {
      "Tamils and Other Natives of India",
      "Tamils and Other Natives of India",
      "Others from Borneo",
      "Tamils and Other Natives of India",
      "Others",
      "Aborigines",
      "Bugis",
      "Achinese",
      "Other Nationalities",
      "Eurasians",
      "Chinese",
      "Other Nationalities",
      "Javanese",
      "Dyaks",
      "Europeans and Americans",
      "Other Nationalities",
      "Boyanese",
      "Other Sumatrans",
      "Chinese"
    };

    double[] othersToMalayAltruisms =
    {
      -0.5,
      -0.5,
      0,
      -0.5,
      0,
      -0.1,
      0.9,
      0.9,
      0,
      0,
      -0.9,
      0,
      0.7,
      0,
      0,
      0,
      0.9,
      0,
      -0.9,
    };

    String[] malayToOtherNames =
    {
      "Aborigines",
      "Achinese",
      "Bugis",
      "Dyaks",
      "Javanese",
      "Chinese",
      "Tamils and Other Natives of India",
      "Europeans and Americans",
      "Eurasians"
    };

    double[] malayToOthersAltruisms =
    {
      0,
      0.9,
      0.9,
      0,
      0.9,
      -0.9,
      -0.5,
      -0.3,
      0
    };

    // create all the non-malay nodes
    for (int i = 0; i < nonMalayNames.length; i++)
    {
      SocialNetVertex newV = new SocialNetVertex();
      newV.name = nonMalayNames[i];
      newV.number = i;

      //otherMap.put(newV.name, newV);
      allOthers.add(newV);
      newV.setRandomColor();
      sng.addVertex(newV);
    }

    // create the malay node
    SocialNetVertex malayV = new SocialNetVertex();
    malayV.name = "Malay";
    malayV.number = 19;
    malayV.setRandomColor();
    sng.addVertex(malayV);

    // create all edges

    // fill in all edges... default is 0
    // stores the vertices we've already seen
    Vector<SocialNetVertex> seen = new Vector<SocialNetVertex>();
    Collection<SocialNetVertex> vertC = sng.getVertices();
    System.out.println("number of vertices: " + vertC.size());
    Iterator<SocialNetVertex> sources = vertC.iterator();
    while (sources.hasNext())
    {
      SocialNetVertex aSource = sources.next();
      seen.add(aSource);
      Iterator<SocialNetVertex> targets = vertC.iterator();
      while (targets.hasNext())
      {
        SocialNetVertex aTarget = targets.next();
        if (!seen.contains(aTarget))
        {
          SocialNetEdge newE = new SocialNetEdge();
          double newSocialValue = 0;

          // first we check if malay are involved in this relationship
          if ((aSource.name.equals("Malay")) || (aTarget.name.equals("Malay")))
          {
            // now that we know malay are involved, check the values
            SocialNetVertex other;
            // set the name of the other group.  Since no edges go from a node
            // to itself, we don't worry about both being malay
            if (!aSource.name.equals("Malay"))
            {
              other = aSource;
            }
            else
            {
              other = aTarget;
            }

            int otherIndex = other.number;
            double otherToMalay = othersToMalayAltruisms[otherIndex];

            // look for a value of malay to others.. if it exists
            double malayToOther = 0;
            for (int i = 0; i < malayToOthersAltruisms.length; i++)
            {
              if (malayToOtherNames[i].equals(other.name))
              {
                malayToOther = malayToOthersAltruisms[i];
              }
            }

            newSocialValue = (otherToMalay + malayToOther) / 2;
          }

          newE.socialValue = newSocialValue;
          newE.length = convertFeelingsIntoLength(newSocialValue);
          setEdgeSpringStrength(newE);

          // NOTE: comment out this if statement if we want to show zero valued edges
          if (!((newSocialValue == 0) && (!showingZeroWeights)))
          {
            sng.addEdge(newE, aSource, aTarget);
          }
        }
      }
    }

    // create labels for all the vertices
    createLabels();

    removeVerticesWithNoEdges();
    setupNet();
  }

  private void createLabels()
  {
    // first remove all labels
    for (int i = 0; i < socialNetContainer.getComponentCount(); i++)
    {
      Component c = socialNetContainer.getComponent(i);
      if (c instanceof JLabel)
      {
        socialNetContainer.remove(c);
      }
    }
    legendPanel.removeAll();

    // next clear the vertexLabels map
    vertexLabels.clear();

    Collection<SocialNetVertex> theVertices = sng.getVertices();
    Iterator<SocialNetVertex> vIterator = theVertices.iterator();
    while (vIterator.hasNext())
    {
      SocialNetVertex theVertex = vIterator.next();
      String labelName = theVertex.name;
      JLabel newLabel = new JLabel(labelName);
      newLabel.setDoubleBuffered(true);
      newLabel.setForeground(socialNetLabelColor);
      Font f = newLabel.getFont();
      FontMetrics fm = newLabel.getFontMetrics(f);
      newLabel.setSize((int) fm.stringWidth(labelName), (int) fm.getHeight());

      vertexLabels.put(theVertex, newLabel);
      labelOffsets.put(newLabel, new Point(0, 0));
      socialNetContainer.add(newLabel);

      JLabel legendLabel = new JLabel(newLabel.getText());
      legendLabel.setForeground(theVertex.color);
      legendPanel.addLabel(legendLabel);
    //socialNetContainer.setComponentZOrder(newLabel, socialNetContainer.getComponentCount() - 1);
    }

  //socialNetContainer.add(vv2D);
  }

  private String getArrayString(int[] input)
  {
    String ret = "[";
    for (int i = 0; i < input.length - 1; i++)
    {
      ret += input[i] + ", ";
    }
    ret += input[input.length - 1] + "]";

    return ret;
  }

  // returns -1 if the conversion fails
  public double convertFeelingsIntoLength(double feelings)
  {
    // if the decimal is out of range, return -1
    if ((feelings > 1) || (feelings < -1))
    {
      return -1;
    }
    else
    {
      return (-0.5 * feelings + 0.5) * maxEdgeLength;
    }
  }

  // places the label according to the location of the vertex
  // doesn't work for 3d view ... yet
  private void setVertexLabel(SocialNetVertex v)
  {
    JLabel theLabel = vertexLabels.get(v);
    Point offset = labelOffsets.get(theLabel);
    if (offset == null)
    {
      System.out.println("offset is null");
    }
    if (theLabel == null)
    {
      System.out.println("null label");
    }

    Point2D vertexP = layout2D.transform(v);
    int x = (int) (vertexP.getX() - theLabel.getSize().width / 2.0);// + offset.x;
    int y = (int) (vertexP.getY() - theLabel.getSize().height / 2.0);// + offset.y;
    theLabel.setLocation(x, y);
  }

  private void setAllVertexLabels()
  {
    Collection<SocialNetVertex> vCollection = sng.getVertices();
    Iterator<SocialNetVertex> vIterator = vCollection.iterator();

    while (vIterator.hasNext())
    {
      setVertexLabel(vIterator.next());
    }
  }

  // used to set labels and make everything setup properly
  // only useful in 2d mode
  private void arrangeLabelOrders()
  {
    int index = 0;
    socialNetContainer.removeAll();
    Collection<SocialNetVertex> vCollection = sng.getVertices();
    Iterator<SocialNetVertex> vIterator = vCollection.iterator();
    while (vIterator.hasNext())
    {
      //socialNetContainer.setComponentZOrder(vertexLabels.get(vIterator.next()), index);
      socialNetContainer.add(vertexLabels.get(vIterator.next()));
      index++;
    }

    //socialNetContainer.setComponentZOrder(vv2D, index);
    socialNetContainer.add(vv2D);
  }

  // remove all vertices that have no edges connected to them
  private void removeVerticesWithNoEdges()
  {
    Vector<SocialNetVertex> toRemove = new Vector<SocialNetVertex>();
    Collection<SocialNetVertex> vCollection = sng.getVertices();
    Iterator<SocialNetVertex> vIterator = vCollection.iterator();
    while (vIterator.hasNext())
    {
      SocialNetVertex v = vIterator.next();
      Collection<SocialNetEdge> connectedEdges = sng.getIncidentEdges(v);
      if (connectedEdges.size() == 0)
      {
        toRemove.add(v);
      }
    }

    for (int i = 0; i < toRemove.size(); i++)
    {
      sng.removeVertex(toRemove.get(i));
    }
  }
}
